package com.ytjj.qmyx.admin.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.github.pagehelper.PageHelper;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.kuaidi100.sdk.contant.CompanyConstant;
import com.ytjj.common.api.CommonPage;
import com.ytjj.common.constants.AlipayConstants;
import com.ytjj.common.constants.AlipayTransConstants;
import com.ytjj.common.exception.ApiException;
import com.ytjj.common.utils.AlipayTransUtil;
import com.ytjj.qmyx.admin.dao.UsersWithdrawalRecordDao;
import com.ytjj.qmyx.admin.mapper.RefundTradeRecordMapper;
import com.ytjj.qmyx.admin.model.MyWxConfig;
import com.ytjj.qmyx.admin.model.RefundTradeRecord;
import com.ytjj.qmyx.admin.model.request.UsersWithdrawalRequest;
import com.ytjj.qmyx.admin.model.response.UsersWithdrawalResponse;
import com.ytjj.qmyx.admin.service.MemberService;
import com.ytjj.qmyx.admin.service.UsersWithdrawalRecordService;
import com.ytjj.qmyx.mall.mapper.PayConfigMapper;
import com.ytjj.qmyx.mall.model.PayConfig;
import com.ytjj.qmyx.mall.model.PayConfigExample;
import com.ytjj.qmyx.users.model.UsersWithdrawalRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * 
 * @Version: 1.0
 */
@Service
@Slf4j
@RefreshScope
public class UsersWithdrawalRecordServiceImpl implements UsersWithdrawalRecordService {

	@Resource
	private UsersWithdrawalRecordDao usersWithdrawalRecordDao;

	@Resource
	private MemberService memberService;
	@Resource
	private AlipayTransUtil alipayTransUtil;
	@Resource
	private PayConfigMapper payConfigMapper;
	public static final String TYPE = "APP";
	public static final String TRADE_TYPE = "APP";
	@Resource
	private RefundTradeRecordMapper refundTradeRecordMapper;
	@Value("${quanmingyanxuan.alipay.trans.appCertPath:}")
	private String appCertPath;
	@Value("${quanmingyanxuan.alipay.trans.alipayRootCertPath:}")
	private String alipayRootCertPath;
	@Value("${quanmingyanxuan.alipay.trans.alipayCertPath:}")
	private String alipayCertPath;

	@Override
	public CommonPage<UsersWithdrawalResponse> selectList(UsersWithdrawalRequest request) {
		PageHelper.startPage(request.getPageNum(), request.getPageSize());
		List<UsersWithdrawalResponse> pageList = usersWithdrawalRecordDao.selectList(request);
		return CommonPage.restPage(pageList);
	}

	@Override
	public void auditSuccess(Integer id) {
		usersWithdrawalRecordDao.auditSuccess(id, memberService.getAdmin().getId(), memberService.getAdmin().getName());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void auditFail(Integer id, String failReason) {
		usersWithdrawalRecordDao.auditFail(id, failReason, memberService.getAdmin().getId(), memberService.getAdmin().getName());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void withdrawalOpera(Integer id) {
		// 获取用户提现审核信息
		UsersWithdrawalRecord withdrawal = usersWithdrawalRecordDao.getWithdrawalById(id);
		if(withdrawal.getStatus() == 2) {
			throw new ApiException("该记录已提现，请勿重复提现(详情联系管理员)！");
		}
		if (3 == withdrawal.getStatus()) {
			throw new ApiException("该记录提现失败，不能重复提现！");
		}
		// 提现金额至用户的微信零钱
		BigDecimal realMoney = withdrawal.getAmount().multiply(new BigDecimal(100));
		boolean result = false;
		try {
			if (null == withdrawal.getType() || 1 == withdrawal.getType()) {
				result = transfer(withdrawal.getPartnerTradeNo(), withdrawal.getOpenid(),
						realMoney.toBigInteger().toString(),
						StringUtils.isEmpty(withdrawal.getDescription()) ? "提现" : withdrawal.getDescription(),
						withdrawal.getUserId());
			}else {
				result = transferByAlipayCertModel(withdrawal.getPartnerTradeNo(), withdrawal.getAmount().toString(),
						withdrawal.getIdentity(), "ALIPAY_LOGON_ID", withdrawal.getName());
			}
		} catch (Exception e) {
			log.error("===={}", e);
			e.printStackTrace();
		}
		log.info("===result==={}", result);
		if(result) {
			usersWithdrawalRecordDao.updateTransfer(withdrawal.getId(), 2);
		} else {
			usersWithdrawalRecordDao.updateTransfer(withdrawal.getId(), 3);
		}

	}

	@Resource
	private AlipayTransConstants alipayTransConstants;
	@Resource
	private AlipayConstants alipayConstants;

	/**
	 * 支付宝转账-证书模式
	 * @param partnerTradeNo
	 * @param amount
	 * @param identity
	 * @param identityType
	 * @param name
	 * @return
	 * @throws AlipayApiException
	 */
	private boolean transferByAlipayCertModel(String partnerTradeNo, String amount, String identity, String identityType, String name) throws AlipayApiException {
		CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
		certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");  //gateway:支付宝网关（固定）https://openapi.alipay.com/gateway.do
		certAlipayRequest.setAppId(alipayTransConstants.getAPPID());  //APPID 即创建应用后生成,详情见创建应用并获取 APPID
		certAlipayRequest.setPrivateKey(alipayTransConstants.getRSA_PRIVATE_KEY());  //开发者应用私钥，由开发者自己生成
		certAlipayRequest.setFormat("json");  //参数返回格式，只支持 json 格式
		certAlipayRequest.setCharset("UTF8");  //请求和签名使用的字符编码格式，支持 GBK和 UTF-8
		certAlipayRequest.setSignType(alipayConstants.getSIGNTYPE());  //商户生成签名字符串所使用的签名算法类型，目前支持 RSA2 和 RSA，推荐商家使用 RSA2。
		certAlipayRequest.setCertPath(appCertPath); //应用公钥证书路径（app_cert_path 文件绝对路径）
		certAlipayRequest.setAlipayPublicCertPath(alipayCertPath); //支付宝公钥证书文件路径（alipay_cert_path 文件绝对路径）
		certAlipayRequest.setRootCertPath(alipayRootCertPath);  //支付宝CA根证书文件路径（alipay_root_cert_path 文件绝对路径）
		AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);

		AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
		AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
		model.setOutBizNo(partnerTradeNo);
		model.setTransAmount(amount);
		model.setProductCode("TRANS_ACCOUNT_NO_PWD");
		model.setBizScene("DIRECT_TRANSFER");
		Participant participant = new Participant();
		participant.setIdentityType(identityType);
		participant.setIdentity(identity);
		participant.setName(name);
		model.setPayeeInfo(participant);
		request.setBizModel(model);

		log.info("===alipay trans account request:{}", JSONObject.toJSONString(request));
		AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);
		log.info("===alipay trans account response:{}", JSONObject.toJSONString(response));
		if(response.isSuccess()){
			log.info("调用成功");
			return true;
		} else {
			log.info("调用失败");
		}
		return false;
	}

	/**
	 * 支付宝转账
	 * @param partnerTradeNo
	 * @param amount
	 * @param identity
	 * @param identityType
	 * @param name
	 * @return
	 */
	private boolean transferByAlipay(String partnerTradeNo, String amount, String identity, String identityType, String name) {
		AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
		AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
		model.setOutBizNo(partnerTradeNo);
		model.setTransAmount(amount);
		Participant participant = new Participant();
		participant.setIdentityType(identityType);
		participant.setIdentity(identity);
		participant.setName(name);
		model.setPayeeInfo(participant);
		model.setProductCode("TRANS_ACCOUNT_NO_PWD");
		model.setBizScene("DIRECT_TRANSFER");
		request.setBizModel(model);
		AlipayClient alipayClient = alipayTransUtil.getAlipayClient();
		try {
			log.info("===alipay trans account request:{}", JSONObject.toJSONString(request));
			//支付宝转账
			AlipayFundTransUniTransferResponse response = alipayClient.execute(request);
			log.info("===alipay trans account response:{}", JSONObject.toJSONString(response));
			if (response.isSuccess()) {
				return true;
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return false;
	}

	public boolean transfer(String partnerTradeNo, String openid, String amount, String desc, Integer userId) throws Exception {
		PayConfigExample payConfigExample = new PayConfigExample();
		payConfigExample.createCriteria().andCompanyEqualTo(CompanyConstant.PLATFORM).andTypeEqualTo(TYPE).andTradeTypeEqualTo(TRADE_TYPE).andVersionEqualTo("v2");
		List<PayConfig> payConfigs = payConfigMapper.selectByExample(payConfigExample);
		PayConfig payConfig = null;
		if (!CollectionUtils.isEmpty(payConfigs)) {
			payConfig = payConfigs.get(0);
		}
		MyWxConfig myWxConfig = new MyWxConfig(payConfig);
		WXPay wxpay = new WXPay(myWxConfig, WXPayConstants.SignType.MD5);
		log.info("===myWxConfig==={}", myWxConfig);

		Map<String, String> data = new HashMap<>();
		data.put("mch_appid", payConfig.getAppid()); //商户账号appid
		data.put("mchid", payConfig.getMchId());     //商户号
		data.put("nonce_str", WXPayUtil.generateNonceStr());
		data.put("partner_trade_no", partnerTradeNo);//商户订单号，需保持唯一性
		data.put("openid", openid);                  //商户appid下，某用户的openid
		data.put("check_name", "NO_CHECK");          //NO_CHECK：不校验真实姓名
		data.put("amount", amount);                  //单位为分
		data.put("desc", desc);                      //备注
		data.put("sign", WXPayUtil.generateSignature(data, payConfig.getWxKey(),
				WXPayConstants.SignType.MD5));      //签名

		log.info("微信转账请求123 param: {}", JSONObject.toJSONString(data));
		String respXml = wxpay.requestWithCert("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers", data, 5000, 1000);
		log.info("===微信转账respData==={}", respXml);
		Map<String, String> respData = WXPayUtil.xmlToMap(respXml);
		if ("SUCCESS".equals(respData.get("return_code"))) {
			if(!"SUCCESS".equals(respData.get("result_code"))){
				String errCode = respData.get("err_code");
				if(errCode.equals("SYSTEMERROR")) {
					Map<String, String> transferInfo = getTransferInfo(wxpay, partnerTradeNo);
					if("SUCCESS".equals(transferInfo.get("return_code")) && "SUCCESS".equals(transferInfo.get("result_code")) && "SUCCESS".equals(transferInfo.get("status"))) {
						//成功
						//记录提现信息
						recordWxRefundRequestInfo(partnerTradeNo, userId, new BigDecimal(amount).divide(new BigDecimal(100)), 1, respXml, JSONObject.toJSONString(data), "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
						return true;
					}
				}
				//失败
				recordWxRefundRequestInfo(partnerTradeNo, userId, new BigDecimal(amount).divide(new BigDecimal(100)), 0, respXml, JSONObject.toJSONString(data), "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
				return false;
			}
			//成功
			recordWxRefundRequestInfo(partnerTradeNo, userId, new BigDecimal(amount).divide(new BigDecimal(100)), 1, respXml, JSONObject.toJSONString(data), "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
			return true;
		}
		recordWxRefundRequestInfo(partnerTradeNo, userId, new BigDecimal(amount).divide(new BigDecimal(100)), 0, respXml, JSONObject.toJSONString(data), "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
		return false;
	}

	/**
	 * 查询 企业付款
	 */
	public Map<String, String> getTransferInfo(WXPay wxpay,String partnerTradeNo) throws Exception {
		Map<String, String> data = new HashMap<>();
		data.put("partner_trade_no", partnerTradeNo);          //商户订单号，需保持唯一性
		String respXml = wxpay.requestWithoutCert("https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo", wxpay.fillRequestData(data), 1000, 1000);
		Map<String, String> response = wxpay.processResponseXml(respXml);
		return response;
	}

	/**
	 * 记录退款、提现时请求微信接口记录
	 */
	public void recordWxRefundRequestInfo(String outTradeNo, Integer userId, BigDecimal amount, Integer status, String responseMessage, String requestMessage, String requestUrl) {
		RefundTradeRecord refundTradeRecord = new RefundTradeRecord();
		refundTradeRecord.setOutTradeNo(outTradeNo);
		refundTradeRecord.setUserId(userId);
		refundTradeRecord.setAmount(amount);
		refundTradeRecord.setStatus(status);
		refundTradeRecord.setResponseMessage(responseMessage);
		refundTradeRecord.setRequestMessage(requestMessage);
		refundTradeRecord.setRequestUrl(requestUrl);
		refundTradeRecord.setCreateTime(new Date());
		refundTradeRecordMapper.insert(refundTradeRecord);
	}
}
